<template>
  <div ref="appContainer" class="app-container home-bg-padding">
    <CustomSearch
      ref="searchForm"
      show-all.sync="false"
      :show-switch-icon="false"
      @search="searchFn"
      @reset="resetFn"
    >
      <template #btns>
        <sec-button
          v-if="permissions(AddUser)"
          type="primary"
          icon="sec-icon-bianji"
          @click="addUser"
          >添加</sec-button
        >
        <sec-tooltip
          class="item"
          effect="dark"
          content="刷新"
          placement="top-start"
        >
          <sec-button
            icon="sec-icon-shuaxin"
            circle
            @click="getList()"
          ></sec-button>
        </sec-tooltip>
      </template>
      <template #search>
        <sec-input
          v-model="searchForm.username"
          class="search-input"
          size="medium"
          placeholder="请输入用户名"
          suffix-icon="sec-icon-sousuo"
          style="width: 300px"
          clearable
        />
      </template>
    </CustomSearch>
    <div class="query-table">
      <sec-table
        v-loading="loading"
        :data="userList"
        size="mini"
        style="width: 100%; height: calc(100% - 42px); overflow-y: scroll"
        stripe
      >
        <sec-table-column
          fixed
          prop="index"
          label="序号"
          width="50"
        ></sec-table-column>
        <sec-table-column
          prop="userNick"
          label="昵称"
          width="120"
        ></sec-table-column>
        <sec-table-column
          prop="username"
          label="用户名"
          width="120"
        ></sec-table-column>
        <sec-table-column
          prop="phone"
          label="手机号"
          width="120"
        ></sec-table-column>
        <sec-table-column prop="roleName" label="角色" width="230">
          <template slot-scope="scope">
            <sec-tag
              v-for="(role, index) in scope.row.roleName"
              :key="index"
              effect="dark"
              :type="['', 'success', 'warning', 'dange'][index % 4]"
              size="small"
              style="margin: 0 10px 5px 0"
              >{{ role }}</sec-tag
            >
          </template>
        </sec-table-column>
        <sec-table-column
          prop="deptName"
          label="部门"
          width="120"
        ></sec-table-column>
        <!--          <sec-table-column-->
        <!--            prop="status"-->
        <!--            label="状态"-->
        <!--            width="100"-->
        <!--          >-->
        <!--            <template slot-scope="scope">-->
        <!--              <sec-tag size="medium">{{ scope.row.status }}</sec-tag>-->
        <!--            </template>-->
        <!--          </sec-table-column>-->
        <sec-table-column prop="createTime" label="创建时间"></sec-table-column>
        <sec-table-column fixed="right" label="操作" width="170">
          <template slot-scope="scope">
            <sec-button
              v-if="permissions(EditUser)"
              type="text"
              size="small"
              icon="sec-icon-bianji"
              @click="editUser(scope.row)"
              >编辑</sec-button
            >
            <sec-button
              v-if="permissions(DeleteUser)"
              type="text"
              size="small"
              icon="el-icon-delete"
              @click="deleteOpen(scope.row)"
              >删除</sec-button
            >
          </template>
        </sec-table-column>
      </sec-table>
      <div class="pagination">
        <sec-pagination
          :current-page.sync="pagination.pageNo"
          :page-size="pagination.pageSize"
          layout="total,prev, pager, next,sizes"
          :total="pagination.totalCount"
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
        ></sec-pagination>
      </div>
    </div>
    <!-- 编辑弹框 -->
    <sec-dialog
      v-if="dialogUserVisible"
      :title="dialogTitle"
      :visible.sync="dialogUserVisible"
      :close-on-click-modal="false"
    >
      <sec-form ref="formEle" :model="form" :rules="rules" label-width="80px">
        <sec-form-item
          v-if="form.showId"
          label="ID"
          :labsec-width="formLabelWidth"
          class="demo-dynamic"
        >
          <sec-input
            v-model="form.userId"
            size="medium"
            autocomplete="off"
            :style="{ width: '230px' }"
            :disabled="form.disableId"
          ></sec-input>
        </sec-form-item>
        <sec-form-item
          label="账号"
          :labsec-width="formLabelWidth"
          prop="username"
        >
          <sec-input
            v-model="form.username"
            size="medium"
            :style="{ width: '230px' }"
            autocomplete="off"
            :disabled="form.disableName"
          ></sec-input>
        </sec-form-item>
        <!--        <sec-form-item-->
        <!--          label="密码策略"-->
        <!--          :labsec-width="formLabelWidth"-->
        <!--          prop="regulationId"-->
        <!--        >-->
        <!--          <sec-select-->
        <!--            v-model="form.regulationId"-->
        <!--            placeholder="请选择"-->
        <!--            :style="{ width: '230px' }"-->
        <!--            @change="handlePswChange"-->
        <!--          >-->
        <!--            <sec-option-->
        <!--              v-for="item in passwordPolicyOptions"-->
        <!--              :key="item.id"-->
        <!--              :label="item.label"-->
        <!--              :value="item.value"-->
        <!--            ></sec-option>-->
        <!--          </sec-select>-->
        <!--        </sec-form-item>-->
        <sec-form-item
          label="密码"
          :labsec-width="formLabelWidth"
          prop="password"
        >
          <sec-input
            v-model="form.password"
            size="medium"
            :style="{ width: '230px' }"
            autocomplete="off"
          ></sec-input>
          <p v-if="passwordRuleText.length" class="password-tip">
            密码要求：
            <span v-for="item in passwordRuleText" :key="item">{{ item }}</span>
          </p>
        </sec-form-item>
        <sec-form-item
          label="用户名"
          :labsec-width="formLabelWidth"
          prop="userNick"
        >
          <sec-input
            v-model="form.userNick"
            size="medium"
            :style="{ width: '230px' }"
            autocomplete="off"
          ></sec-input>
        </sec-form-item>
        <sec-form-item
          label="邮箱"
          :labsec-width="formLabelWidth"
          prop="userMail"
        >
          <sec-input
            v-model="form.userMail"
            size="medium"
            :style="{ width: '230px' }"
            autocomplete="off"
          ></sec-input>
        </sec-form-item>
        <sec-form-item
          label="所属部门"
          :labsec-width="formLabelWidth"
          prop="deptId"
        >
          <sec-cascader
            v-model="form.deptId"
            clearable
            size="medium"
            :options="department"
            :props="{ ...defaultProps, checkStrictly: true }"
            :show-all-levels="false"
            @change="handleChange"
          ></sec-cascader>
        </sec-form-item>
        <sec-form-item
          label="手机号"
          :labsec-width="formLabelWidth"
          prop="phone"
        >
          <sec-input
            v-model="form.phone"
            size="medium"
            :style="{ width: '180px' }"
            autocomplete="off"
          ></sec-input>
        </sec-form-item>
        <sec-form-item
          label="角色名称"
          :labsec-width="formLabelWidth"
          prop="roleId"
        >
          <sec-select
            v-model="form.roleId"
            :style="{ width: '330px' }"
            placeholder="请选择"
            size="medium"
            multiple
          >
            <sec-option
              v-for="item in roleList"
              :key="item.roleId"
              :label="item.roleName"
              :value="item.roleId"
            ></sec-option>
          </sec-select>
        </sec-form-item>
        <!--        <sec-form-item-->
        <!--          label="状态"-->
        <!--          :labsec-width="formLabelWidth"-->
        <!--          prop="lockFlag"-->
        <!--        >-->
        <!--          <sec-radio-group v-model="form.lockFlag">-->
        <!--            <sec-radio-->
        <!--              label="0"-->
        <!--              border-->
        <!--            >有效</sec-radio>-->
        <!--            <sec-radio-->
        <!--              label="1"-->
        <!--              border-->
        <!--            >锁定</sec-radio>-->
        <!--          </sec-radio-group>-->
        <!--        </sec-form-item>-->

        <sec-form-item
          v-if="form.showTime"
          label="创建时间"
          :labsec-width="formLabelWidth"
        >
          <sec-input
            v-model="form.createTime"
            autocomplete="off"
            :style="{ width: '230px' }"
            :disabled="form.disableTime"
          ></sec-input>
        </sec-form-item>
      </sec-form>
      <div slot="footer" class="dialog-footer">
        <sec-button
          icon="el-icon-circle-close"
          @click="dialogUserVisible = false"
          >取 消</sec-button
        >
        <sec-button type="primary" icon="el-icon-check" @click="confirmBtn">{{
          btn
        }}</sec-button>
      </div>
    </sec-dialog>
    <!-- 编辑上传 -->
    <sec-dialog
      title="用户信息导入"
      class="global-custom-upload-style"
      :visible.sync="dialogUploadVisible"
      :close-on-click-modal="false"
    >
      <sec-upload class="upload-demo" drag action="/upload" multiple>
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">
          将文件拖到此处，或
          <em>点击上传</em>
        </div>
        <div slot="tip" class="sec-upload__tip">
          只能上传jpg/png文件，且不超过500kb
        </div>
      </sec-upload>
      <div slot="footer" class="dialog-footer">
        <sec-button
          icon="el-icon-circle-close"
          @click="dialogUploadVisible = false"
          >取 消</sec-button
        >
        <sec-button
          type="primary"
          icon="el-icon-check"
          @click="dialogUploadVisible = false"
          >确定</sec-button
        >
      </div>
    </sec-dialog>
  </div>
</template>

<script>
import { mapGetters } from 'vuex'
import CryptoJS from 'crypto-js'
import { AddUser, DeleteUser, EditUser } from '@/const/permissions'
import http from '@/utils/http'
import { mixin } from './mixin'
import pagination from '@/utils/mixins/pagination'
import { CustomSearch } from '@/components'
import debounce from 'lodash/debounce'
// 密码规则
let CURRENTRULE = ''
let ignorePassword = 'no'
let isEdit = false

export default {
  name: 'AccessUser',
  components: {
    CustomSearch
  },
  mixins: [mixin, pagination],
  data() {
    const checkPsw = async function (rule, value, callback) {
      if (ignorePassword === 'yes' && !value) {
        callback()
        return
      }

      const val = value.trim()
      if (!val) {
        callback(new Error('请输入密码'))
        return
      }
      if (val.length < 8) {
        callback(new Error('密码长度最少为8位'))
        return
      }

      const { code } = await http.checkPassword({
        password: val,
        regulationId: CURRENTRULE
      })

      if (code === '200') {
        callback()
      } else {
        callback(new Error('输入的密码不符合规则！'))
      }
    }
    const checkIphone = async function (rule, value, callback) {
      if (!value.trim()) {
        callback(new Error('请输入手机号'))
        return
      }

      if (isEdit) {
        if (!/^1\d{10}$/.test(value) && !/^\d{3}\*{4}\d{4}$/.test(value)) {
          callback('请输入正确的手机格式')
          return
        }
      } else {
        if (!/^1\d{10}$/.test(value)) {
          callback('请输入正确的手机格式')
          return
        }
      }

      callback()
    }
    const checkEmail = async function (rule, value, callback) {
      const reg = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/
      if (reg.test(value)) {
        callback()
      } else {
        callback('请输入正确的邮箱格式')
      }
    }
    return {
      passwordRuleText: '',
      DeleteUser,
      AddUser,
      EditUser,
      dialogTitle: '编辑',
      dialogFlag: 'EDIT',
      filterText: '',
      department: null,
      userListInfo: [],
      defaultProps: {
        children: 'children',
        label: 'name',
        value: 'id'
      },
      user: {
        userId: '',
        password: '',
        regulationId: '',
        phone: '',
        roleName: '',
        roleId: [],
        username: '',
        lockFlag: '',
        roleList: [],
        deptId: '',
        createTime: '',
        disableId: false,
        disableName: false,
        disableTime: false,
        userNick: '',
        userMail: ''
      },
      dialogUserVisible: false,
      dialogUploadVisible: false,
      formLabelWidth: '120px',
      rules: {
        username: {
          required: true,
          message: '请输入用户名',
          trigger: 'change'
        },
        userNick: {
          required: true,
          message: '请输入用户名',
          trigger: 'change'
        },
        userMail: {
          required: true,
          trigger: 'change',
          validator: checkEmail
        },
        phone: {
          required: true,
          validator: checkIphone,
          trigger: 'change'
        },
        password: {
          required: true,
          validator: checkPsw,
          trigger: 'change'
        },
        deptId: {
          required: true,
          message: '请选择所属部门',
          trigger: 'change'
        },
        lockFlag: { required: true, message: '请选择状态', trigger: 'change' },
        roleId: { required: true, message: '请选择角色', trigger: 'change' },
        regulationId: {
          required: true,
          message: '请选择密码策略',
          trigger: 'change'
        }
      },
      loading: false,
      selectDepartId: '',
      btn: '确定',
      roleList: [],
      passwordPolicyOptions: [],
      searchForm: {}
    }
  },
  computed: {
    ...mapGetters(['permissions']),
    form: function () {
      return this.user
    },
    userList: function () {
      return this.userListInfo.map(
        (
          {
            deptId,
            username,
            phone,
            createTime,
            userId,
            deptName,
            roleList,
            lockFlag,
            password,
            regulateId,
            userMail,
            userNick
          },
          index
        ) => {
          return {
            index: ++index,
            deptId: [deptId],
            username,
            phone,
            createTime,
            roleId: roleList.map((e) => e.roleId),
            userId,
            roleName: roleList.map((e) => e.roleName),
            deptName,
            roleList,
            password,
            lockFlag,
            regulationId: regulateId,
            status: lockFlag === '0' ? '有效' : '锁定',
            userMail,
            userNick
          }
        }
      )
    }
  },
  watch: {
    filterText(val) {
      this.$refs.tree.filter(val)
    },
    selectDepartId: function (val) {
      this.getList()
    },
    'searchForm.username': {
      handler: debounce(function () {
        this.searchFn()
      }, 1000)
    }
  },
  created: function () {
    // this.fetchPswOptions()
    this.fetchDepartment()
    this.getList()
    this.fetchRoleList()
  },
  methods: {
    fetchRoleList: function () {
      http.getRoleList().then((res) => {
        this.roleList = res.data
      })
    },
    getList(
      param = {
        pageNo: this.pagination.pageNo,
        pageSize: this.pagination.pageSize
      }
    ) {
      this.loading = true
      if (param.username === '') {
        Reflect.deleteProperty(param, 'username')
      }
      http.getUserList(param).then(({ data }) => {
        this.loading = false
        const { rows, totalRows, pageNo, pageSize } = data
        this.userListInfo = rows
        this.pagination = {
          ...this.pagination,
          pageNo,
          pageSize,
          totalCount: totalRows
        }
      })
    },
    fetchPswOptions(option) {
      this.loading = true
      http.getPwdPolicyOptions().then((res) => {
        this.loading = false
        const { data } = res
        this.passwordPolicyOptions = data.map(
          ({ regulateId, regulateName, defaultStatus, description }) => ({
            value: regulateId,
            label: regulateName,
            description: description,
            checked: defaultStatus
          })
        )
      })
    },
    handlePswChange(aSelect) {
      const oCheck = this.passwordPolicyOptions.find(
        ({ value }) => value === aSelect + ''
      )

      CURRENTRULE = oCheck ? oCheck['value'] : ''

      this.passwordRuleText = oCheck.description.split('\n')
    },
    handleChange(aSelect) {
      this.user.deptId = aSelect
    },
    editUser(user) {
      console.log(user, '🌈')

      isEdit = true
      this.dialogUserVisible = true
      let found = false

      const id = Array.isArray(user.deptId)
        ? user.deptId[user.deptId.length - 1]
        : ''
      /**
       * @description 递归查找
       * *** 当前递归是深度优先遍历的策略.
       * *** 嵌套for循环遍历的跳出的确是一个小的问题，可以借助try catch之外就只能通过flag方式实现了
       */
      const recursionFindById = (arr, id) => {
        if (!Array.isArray(arr)) return

        for (let i = 0; i < arr.length; i++) {
          const node = arr[i]
          if (node.id === id) {
            found = node
            break
          }
          if (Array.isArray(node.children) && !found) {
            recursionFindById(node.children, id)
          }
        }
      }

      recursionFindById(this.department, id)

      const idLink = [found.id]
      // // 溯源id链
      const findParentId = (node) => {
        const parent = node.parent

        if (!parent) return

        idLink.unshift(parent.id)

        if (parent.id === id) {
          return
        } else {
          findParentId(parent)
        }
      }

      findParentId(found)
      this.user = {
        ...user,
        deptId: idLink,
        disableId: true,
        disableName: true,
        disableTime: true,
        showId: true,
        showTime: true
      }
      this.btn = '修改'
      this.dialogTitle = '编辑'
      this.dialogFlag = 'EDIT'
      this.rules.password.required = false
      // 忽略
      ignorePassword = 'yes'

      const oCheck = this.passwordPolicyOptions.find(
        ({ value }) => value === this.user.regulationId + ''
      )

      CURRENTRULE = oCheck ? oCheck['value'] : ''

      this.passwordRuleText = oCheck ? oCheck.description.split('\n') : []
    },
    addUserByFile(user) {
      this.dialogUploadVisible = true
    },
    exportUserFile(user) {
      // this.dialogUploadVisible = true
    },
    addUser(user) {
      this.dialogUserVisible = true
      const oCheck = this.passwordPolicyOptions.find(({ checked }) => !!checked)

      CURRENTRULE = oCheck ? oCheck['value'] : ''

      // const tempText = `密码长度为8-20\n不允许包含空格\n连续字符不能超过3个\n键盘连续按键不能超过3个\n至少包含2个大写字母\n至少包含2个小写字母\n至少包含2个数字\n至少包含2个特殊字符[@$!%*#_~?&^].`
      this.passwordRuleText = oCheck ? oCheck.description.split('\n') : []

      // 重置

      this.user = {
        userId: '',
        password: '',
        // 默认策略
        regulationId: CURRENTRULE,
        phone: '',
        roleName: '',
        roleId: [],
        username: '',
        lockFlag: '',
        roleList: [],
        deptId: '',
        createTime: '',
        disableId: false,
        disableName: false,
        disableTime: false,
        userNick: '',
        userMail: ''
      }
      this.btn = '确认'
      this.dialogTitle = '添加'
      isEdit = false
      this.dialogFlag = 'ADD'
      this.rules.password.required = true
      ignorePassword = 'no'
    },
    deleteUser(user) {
      this.dialogUserVisible = true
      this.user = user
    },
    filterNode(value, data) {
      if (!value) return true
      return data.name.indexOf(value) !== -1
    },
    currentChange(node, data) {
      this.selectDepartId = node.id
    },
    deleteOpen(row) {
      this.$confirm(
        `此操作将永久删除用户（用户名:${row.username}）, 是否继续?`,
        '提示',
        {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          closeOnClickModal: false,
          type: 'warning'
        }
      )
        .then(() => {
          http
            .deleteUser({ userId: row.userId, username: row.username })
            .then(() => {
              this.$message({
                type: 'success',
                message: '删除成功!'
              })
              this.getList()
            })
        })
        .catch((e) => {
          console.error(e)
          this.$message({
            type: 'info',
            message: '已取消删除'
          })
        })
    },
    confirmBtn() {
      this.$refs.formEle.validate(async (valid) => {
        if (valid) {
          // 加密
          const {
            code: iCode,
            data: { key }
          } = await http.getPublicKey({ name: this.user.username })

          if (iCode !== '200') {
            console.error('fetch error ', iCode)
            return
          }

          let encryptionPsw = ''

          if (this.user.password) {
            encryptionPsw = CryptoJS.AES.encrypt(
              CryptoJS.enc.Utf8.parse(this.user.password),
              CryptoJS.enc.Utf8.parse(key),
              {
                mode: CryptoJS.mode.ECB,
                padding: CryptoJS.pad.Pkcs7
              }
            )
          }

          let encryptionPhone = ''

          if (/^1\d{10}$/g.test(this.user.phone)) {
            encryptionPhone = CryptoJS.AES.encrypt(
              CryptoJS.enc.Utf8.parse(this.user.phone),
              CryptoJS.enc.Utf8.parse(key),
              {
                mode: CryptoJS.mode.ECB,
                padding: CryptoJS.pad.Pkcs7
              }
            )
          }

          const param = {
            $lockFlag: this.user.lockFlag === '0' ? '有效' : '锁定',
            userId: this.user.userId,
            username: this.user.username,
            password: encryptionPsw.toString(),
            // todo 所属部门，传参是最后一级的id,这里不对，应该是传数组['1','2']
            deptId: this.user.deptId[this.user.deptId.length - 1],
            phone: encryptionPhone.toString(),
            role: this.user.roleId,
            deptName: '',
            regulateId: this.user.regulationId,
            lockFlag: this.user.lockFlag,
            createTime: '',
            userNick: this.user.userNick,
            userMail: this.user.userMail
          }

          if (this.dialogFlag === 'ADD') {
            http.addUser(param).then((res) => {
              const { code } = res

              if (code === '200') {
                this.$message({
                  type: 'success',
                  message: '添加成功!'
                })
                this.dialogUserVisible = false

                this.getList()
              }
            })
          } else if (this.dialogFlag === 'EDIT') {
            http.updateUser(param).then((res) => {
              const { code } = res

              if (code === '200') {
                this.$message({
                  type: 'success',
                  message: '更新成功!'
                })
                this.dialogUserVisible = false

                this.getList()
              }
            })
          }
        } else {
          console.log('error submit!!')
          return false
        }
      })
    }
  }
}
</script>

<style scoped lang="scss">
.left-layout {
  width: 200px;
  float: left;
}
.password-tip {
  margin: 0;
  padding: 0;
  line-height: 1.5;
  font-size: 12px;
  color: #999999;
  padding-top: 5px;
  & > span:not(:first-child) {
    display: inherit;
    &::before {
      content: '';
      display: inline-block;
      padding: 2px;
      background: #999999;
      border-radius: 2px;
      margin-right: 5px;
      float: left;
      margin-top: 7px;
    }
  }
}
.right-layout {
  float: left;
  // margin-left: 20px;
  font-size: 14px;
  min-width: 700px;
  width: 100%;
  padding: 0 20px 0 0px;
  .line {
    padding: 10px 0;
    &.page {
      text-align: right;
    }
  }
}
.query-table {
  padding: 8px;
  background: #fff;
  flex: 1;
  height: 1%;
  .operate {
    font-size: 12px;
  }
  .idot {
    width: 8px;
    height: 8px;
    background: #19be6b;
    border-radius: 50%;
    display: inline-block;
    margin-right: 5px;
  }
  .sec-icon-bangzhu1 {
    margin-left: 3px;
    color: rgb(45, 140, 240);
  }
  .pagination {
    text-align: right;
    padding-top: 8px;
    .el-pagination {
      padding-right: 0;
    }
    .el-pagination__sizes {
      margin: 0;
    }
    .el-pagination .el-pagination__sizes .el-select .el-input {
      margin-right: 0;
    }
  }
  .el-table {
    .el-table-column--selection {
      .cell {
        padding-left: 14px;
      }
    }
    .el-table__body {
      width: 100%;
      // 使表格兼容safari，不错位
      table-layout: fixed !important;
    }
  }
}
.item {
  width: 30px;
}
</style>
